package l1j.server.server.model.item;

import java.io.File;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

import l1j.opqlo.NewSystem.各項記錄輸出;
import l1j.opqlo.NewSystem.ItemLevelUp.ItemLevelUpTable;
import l1j.opqlo.Server.L1World.L1World;
import l1j.server.server.datatables.ItemTable;
import l1j.server.server.model.L1Inventory;
import l1j.server.server.model.Instance.L1ItemInstance;
import l1j.server.server.model.Instance.L1PcInstance;
import l1j.server.server.serverpackets.S_ItemStatus;
import l1j.server.server.serverpackets.S_ServerMessage;
import l1j.server.server.serverpackets.S_SystemMessage;
import l1j.server.server.utils.Random;

@XmlAccessorType(XmlAccessType.FIELD)
public class L1TreasureBox {

	private static Logger _log = Logger.getLogger(L1TreasureBox.class.getName());

	@XmlAccessorType(XmlAccessType.FIELD)
	@XmlRootElement(name = "TreasureBoxList")
	private static class TreasureBoxList implements Iterable<L1TreasureBox> {
		@XmlElement(name = "TreasureBox")
		private List<L1TreasureBox> _list;

		@Override
		public Iterator<L1TreasureBox> iterator() {
			return _list.iterator();
		}
	}

	@XmlAccessorType(XmlAccessType.FIELD)
	private static class Item {
		@XmlAttribute(name = "ItemId")
		private int _itemId;

		@XmlAttribute(name = "Count")
		private int _count;

		private int _chance;

		@XmlAttribute(name = "Chance")
		private void setChance(final double chance) {
			_chance = (int) (chance * 10000);
		}
		// 道具天數刪除系統
		@XmlAttribute(name = "Day")
		private int _day;
		//opqlo 開箱賦予強化值
		@XmlAttribute(name = "Enchant")
		private int _enchant;
		//opqlo 開箱賦予等級
		@XmlAttribute(name = "Level")
		private int _level;

		public int getItemId() {
			return _itemId;
		}

		public int getCount() {
			return _count;
		}

		public double getChance() {
			return _chance;
		}
		// 道具天數刪除系統
		public int getDay() {
			return _day;
		}
		//opqlo 開箱賦予強化值
		public int getEnchant(){
			return _enchant;
		}
		//opqlo 開箱賦予等級
		public int getLevel(){
			return _level;
		}
	}

	private static enum TYPE {
		RANDOM, SPECIFIC
	}

	private static final String PATH = "./data/xml/Item/TreasureBox.xml";

	private static final HashMap<Integer, L1TreasureBox> _dataMap = new HashMap<Integer, L1TreasureBox>();

	/**
	 * 指定されたIDのTreasureBoxを返す。
	 * 
	 * @param id
	 *            - TreasureBoxのID。普通はアイテムのItemIdになる。
	 * @return 指定されたIDのTreasureBox。見つからなかった場合はnull。
	 */
	public static L1TreasureBox get(final int id) {
		return _dataMap.get(id);
	}

	@XmlAttribute(name = "ItemId")
	private int _boxId;

	@XmlAttribute(name = "Type")
	private TYPE _type;

	private int getBoxId() {
		return _boxId;
	}

	private TYPE getType() {
		return _type;
	}

	@XmlElement(name = "Item")
	private CopyOnWriteArrayList<Item> _items;

	private List<Item> getItems() {
		return _items;
	}

	private int _totalChance;

	private int getTotalChance() {
		return _totalChance;
	}

	private void init() {
		for (final Item each : getItems()) {
			_totalChance += each.getChance();
			if (ItemTable.getInstance().getTemplate(each.getItemId()) == null) {
				getItems().remove(each);
				_log.warning("道具編號 " + each.getItemId() + " 不存在。");
			}
		}
		if (getTotalChance() != 0 && getTotalChance() != 1000000) {
			_log.warning("ID " + getBoxId() + " 機率的總和未滿100% 。");
		}
	}

	public static void load() {
		try {
			final JAXBContext context = JAXBContext
					.newInstance(L1TreasureBox.TreasureBoxList.class);

			final Unmarshaller um = context.createUnmarshaller();

			final File file = new File(PATH);
			final TreasureBoxList list = (TreasureBoxList) um.unmarshal(file);

			for (final L1TreasureBox each : list) {
				each.init();
				_dataMap.put(each.getBoxId(), each);
			}
		} catch (final Exception e) {
			_log.log(Level.SEVERE, PATH + " 的寶袋載入失敗！", e);
			System.exit(0);
		}
	}

	/**
	 * TreasureBoxを開けるPCにアイテムを入手させる。PCがアイテムを持ちきれなかった場合は アイテムは地面に落ちる。
	 * 
	 * @param pc
	 *            - TreasureBoxを開けるPC
	 * @return 開封した結果何らかのアイテムが出てきた場合はtrueを返す。 持ちきれず地面に落ちた場合もtrueになる。
	 */
	public boolean open(final L1PcInstance pc) {
		L1ItemInstance item = null;
		final L1ItemInstance openbox = pc.getInventory().findItemId(getBoxId());
		boolean 是否鑑定 = false;
		if (getType().equals(TYPE.SPECIFIC)) {
			// 出るアイテムが決まっているもの
			for (final Item each : getItems()) {
				item = ItemTable.getInstance().createItem(each.getItemId());
				if (item != null) {
					item.setCount(each.getCount());

					// 道具天數刪除系統
					final int delday = each.getDay();
					if (delday > 0) {
						final Timestamp deleteDay = new Timestamp(System.currentTimeMillis()+ (86400000 * delday));
						item.setDeleteDate(deleteDay);
						是否鑑定 = true;
					}
					// end
					//opqlo 開箱賦予強化數值
					if(item.getItem().getType2()!=0){
						final int EnchantLv = each.getEnchant();
						if(EnchantLv !=0){
							item.setEnchantLevel(EnchantLv);
							是否鑑定 = true;
						}
						//opqlo 開箱賦予等級
						if(each.getLevel() >1){
							item.setLevel(each.getLevel());
							if(ItemLevelUpTable.getInstance().getTemplate(item.getItemId()) !=null){
								ItemLevelUpTable.getInstance().getLevelStatus(item);
							}
							是否鑑定 = true;
						}else{
							item.setLevel(1);
						}
					}
					storeItem(pc, item);
				}
			}

		} else if (getType().equals(TYPE.RANDOM)) {
			// 出るアイテムがランダムに決まるもの
			int chance = 0;

			final int r = Random.nextInt(getTotalChance());

			for (final Item each : getItems()) {
				chance += each.getChance();

				if (r < chance) {
					item = ItemTable.getInstance().createItem(each.getItemId());
					if (item != null) {
						item.setCount(each.getCount());
						// 道具天數刪除系統
						final int delday = each.getDay();
						if (delday > 0) {
							final Timestamp deleteDay = new Timestamp(System.currentTimeMillis()+ (86400000 * delday));
							item.setDeleteDate(deleteDay);
						}
						//opqlo 開箱賦予強化數值
						if(item.getItem().getType2()!=0){
							final int EnchantLv = each.getEnchant();
							item.setEnchantLevel(EnchantLv);
							pc.sendPackets(new S_ItemStatus(item));//opqlo 線上更新
						}
						// end
						if(openbox.getItemId() == 255551){//	紅包袋
							if(item.getItem().getType2() !=0){
								item.setBless(0);
								是否鑑定 = true;
							}
						}
						storeItem(pc, item);
						if (item.getItem().getBroad() && delday == 0) {// 開出廣播加入天數＝＝0判斷
							final StringBuilder aa =new StringBuilder();
							aa.append(pc.getName())
							.append("開啟《").append(openbox.getName())
							.append("》取得《").append(item.getName()).append("》!!");
							L1World.getInstance().broadcastPacketToAll(pc , new S_SystemMessage(aa.toString()));
							//TODO 使用物品記錄by opqlo
							aa.append("	流水號: ").append(item.getId()).append("IP(").append(pc.getNetConnection().getIp().toString()).append("	)時間:(").append(new Timestamp(System.currentTimeMillis())).append(")。");
							各項記錄輸出.LogSave(1,aa.toString());
							aa.delete(0, aa.length());
							//TODO 使用物品記錄by opqlo
						}
					}
					break;
				}
			}
		}

		if (item == null) {
			return false;
		} else {
			final int itemId = getBoxId();

			if(是否鑑定 ==true){
				item.setIdentified(true);
				pc.sendPackets(new S_ItemStatus(item));//opqlo 線上更新
			}
			// 魂の結晶の破片、魔族のスクロール、ブラックエントの実
			if (itemId == 40576 || itemId == 40577 || itemId == 40578
					|| itemId == 40411 || itemId == 49013) {
				pc.death(null); // キャラクターを死亡させる
			}
			return true;
		}
	}

	private static void storeItem(final L1PcInstance pc, final L1ItemInstance item) {
		L1Inventory inventory;

		if (pc.getInventory().checkAddItem(item, item.getCount()) == L1Inventory.OK) {
			inventory = pc.getInventory();
		} else {
			if(!item.getItem().isTradable() || item.getDeleteDate() !=null){
				inventory = null;
				pc.sendPackets(new S_SystemMessage("不可轉移的物品在掉落地上後就消失了。"));
			}else{
				// 持てない場合は地面に落とす 処理のキャンセルはしない（不正防止）
				inventory = L1World.getInstance().getInventory(pc.getLocation());
			}
		}
		if(inventory != null){
			inventory.storeItem(item);
			pc.sendPackets(new S_ServerMessage(403, item.getLogName())); // %0を手に入れました。
		}
	}



	public L1ItemInstance testBox(){
		int chance = 0;
		final int r = Random.nextInt(getTotalChance());
		L1ItemInstance item;
		for (final Item each : getItems()) {
			chance += each.getChance();
			if (r < chance) {
				item = ItemTable.getInstance().createItem(each.getItemId());
				if (item != null) {
					item.setCount(each.getCount());
					return item;
					// 道具天數刪除系統
				}
			}
		}
		return null;
	}
}
